package net.bingosoft.common.service;

import java.lang.reflect.Method;

import net.bingosoft.common.config.Config;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import bingo.persister.Persister;

/**
 * 2007-12-11 下午01:16:26
 * Author:yangdongyu(yangdy@bingosoft.net)
 * ReadMe:Service工厂,用于生产service,提供对特定更新方法的事务代理
 * ChangeLog:
 */
public class ServiceFactoryBean implements FactoryBean,ApplicationContextAware{

	private static final boolean ENABLE_METHOD_TRANSACTION_PREFIX = Config.getBoolean("ENABLE_METHOD_TRANSACTION_PREFIX", true);
	private static final String TRANSACTION_METHOD_PREFIXS = Config.getString("TRANSACTION_METHOD_PREFIXS", "create,update,delete,add,remove,save,insert,drop");
	private ApplicationContext ctx;
	/**
	 * 要代理的类的全路径
	 */
	private String target ;


	/**
	 * 获取service
	 * @param target
	 * @return
	 */
	protected Object createSingletonServiceProxyBean(String target){
		TransactionProxy proxyService = new TransactionProxy();
		Object serviceProxy = null;
		try {

			serviceProxy = proxyService.proxyTransaction(Class.forName(target));
			ctx.getAutowireCapableBeanFactory().autowireBeanProperties(serviceProxy,AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, false);

		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		return serviceProxy;
	}


	public Object getObject() throws Exception {
		return createSingletonServiceProxyBean(target);
	}


	public Class getObjectType() {
		Object obj = null;
		try {
			obj = getObject();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return (obj != null) ? obj.getClass() : BaseService.class;
	}


	public boolean isSingleton() {
		return true;
	}



	public String getTarget() {
		return target;
	}


	public void setTarget(String target) {
		this.target = target;
	}


	/**
	 * 2007-5-10 下午04:47:26
	 * Author:yangdongyu(yangdy@bingosoft.net)
	 * ReadMe:事务处理类,代替用户管理事务
	 * 使用方法：向proxyTransaction(Class<T> dest)传入要管理的类
	 *         该方法会动态生成一个传入对象的子类,子类方法的调用会自动封装事务
	 * ChangeLog:2.0 添加泛型支持
	 */
	public static class TransactionProxy implements MethodInterceptor{
		private static final Log log = LogFactory.getLog(TransactionProxy.class);
		/**
		 * 方法拦截器,当调用被增强类的实例方法时会转向此处执行
		 * @param object 被代理类的实例
		 * @param method 被代理类的方法
		 * @param args 调用方法所需参数
		 * @param methodProxy 代理方法
		 */
		public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
			Object result = null;
			//判断方法是否带有事务
			String methodName = method.getName();
			boolean useTransaction = method.isAnnotationPresent(Transaction.class);
			if(!useTransaction && ENABLE_METHOD_TRANSACTION_PREFIX){//保持兼容以前版本
				String []transactionRequiredMethodPrefix = TRANSACTION_METHOD_PREFIXS.split(",");
				for(String prefix : transactionRequiredMethodPrefix){
					if(methodName.startsWith(prefix)){
						useTransaction = true;
						break;
					}
				}
			}

			if(!useTransaction || "getPersister".equals(method.getName())){
				return methodProxy.invokeSuper(object, args);
			}

			Persister persister;
			if(!(object instanceof IPersisterAware)){
				throw new RuntimeException("被代理的目标类必须实现接口net.bingosoft.common.service.IPersisterAware,请检查...");
			}else{
				persister = ((IPersisterAware)object).getPersister();
			}

			if(useTransaction){
				try {
					log.debug("开启事务...");
					persister.beginTransaction();
					result = methodProxy.invokeSuper(object, args);
					persister.commit();
					log.debug("提交事务...");
				} catch (Throwable ex) {
					persister.rollback();
					log.error("调用方法: " + methodName + " 发生[" + ex.getMessage() + "]异常,事务回滚...",ex);
					throw ex;
				}
			}
			return result;
		}
		/**
		 * 对目标类进行事务增强 
		 * @param dest 目标类
		 * @return 目标类的一个子类实例,该实例代理事务处理
		 */
		@SuppressWarnings("unchecked")
		public  final <T> T proxyTransaction(Class<T> dest) {
			Enhancer enhancer = new Enhancer();
			enhancer.setSuperclass(dest);
			enhancer.setCallback(this);
			return (T)enhancer.create();
		}

	}




	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		this.ctx = applicationContext;

	}




}
